home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998 November: Tool Chest / Dev.CD Nov 98 TC.toast / Sample Code / Snippets / Sound / SndPlayDoubleBuffer / _source / AIFF.c next >
Encoding:
C/C++ Source or Header  |  1996-11-15  |  9.7 KB  |  247 lines  |  [TEXT/CWIE]

  1. /*
  2. **    Apple Macintosh Developer Technical Support
  3. **
  4. **    Routine demonstrating how to parse AIFF sound files.
  5. **
  6. **    by Mark Cookson, Apple Developer Technical Support
  7. **
  8. **    File:    AIFF.c
  9. **
  10. **    Copyright ©1996 Apple Computer, Inc.
  11. **    All rights reserved.
  12. **
  13. **    You may incorporate this sample code into your applications without
  14. **    restriction, though the sample code has been provided "AS IS" and the
  15. **    responsibility for its operation is 100% yours.  However, what you are
  16. **    not permitted to do is to redistribute the source as "Apple Sample
  17. **    Code" after having made changes. If you're going to re-distribute the
  18. **    source, we require that you make it clear in the source that the code
  19. **    was descended from Apple Sample Code, but that you've made changes.
  20. */
  21.  
  22. #include "AIFF.h"
  23.  
  24. /*
  25.     need to substitute this code where using long doubles
  26.  
  27. typedef struct myLongDouble {
  28.     double    firstHalf;
  29.     double    secondHalf;
  30. } myLongDouble;
  31.  
  32. */
  33.  
  34. /* Given an AIFF File gets the sample rate and other relavent pieces of information.
  35.    This has been modified from its orignal form found in the Develop 11 MultiBuffer source. */
  36. /*-----------------------------------------------------------------------*/
  37.         OSErr    ASoundGetAIFFHeader        (SoundInfoPtr theSoundInfo,
  38.                                         long *dataStart,
  39.                                         long *length)
  40. /*-----------------------------------------------------------------------*/
  41. {
  42.     ChunkTemplatePtr        chunkTemplate        = nil;            /* ...for ease of access */
  43.     unsigned long            type                = kInit;
  44.     long                    filePosition        = kInit,
  45.                             byteCount            = kInit;
  46.     Fixed                    sampleRate            = kInit;
  47.     unsigned short            chunkFlags            = kInit;        /* remember chunks we've seen */
  48.     OSErr                    err                    = noErr;
  49.     char                    chunkBuffer[kChunkBufferSize];
  50.  
  51.     *dataStart = kInit;
  52.  
  53.     /*  Parse the AIFF (or AIFC) header */
  54.  
  55.     do {
  56.         /*    Position ourselves at the beginning of the next chunk and read in
  57.             a hunk-o-data... */
  58.         err = SetFPos (theSoundInfo->refNum, fsFromStart, filePosition);
  59.         if (err != noErr) {
  60.             DebugPrint ("\pSetFPos failed!");
  61.             break;
  62.         }
  63.  
  64.         byteCount = kChunkBufferSize;
  65.         err = FSRead (theSoundInfo->refNum, &byteCount, chunkBuffer);                        /* read a chunk */
  66.         if ((err != noErr) && (err != eofErr)) {
  67.             DebugPrint ("\pFSRead failed!");
  68.             break;
  69.         }
  70.  
  71.         /*    Now, position the template over the data... */
  72.         chunkTemplate = (ChunkTemplatePtr) chunkBuffer;
  73.  
  74.         /* assume a failure and break out of the do {} while loop if the next case isn't found.
  75.            if the case is found and no other error is detected, then each case needs to set noErr */
  76.         err = badFileFormat;                                
  77.         switch (chunkTemplate->generic.ckID) {
  78.             case FORMID:                                                                    /* Format Version Chunk? */
  79.                 /*    make sure that this is a standard, noncompressed AIFF file. */
  80.                 if ((chunkFlags & kFORM) == false) {                                        /* see if this chunk already exists */
  81.                     chunkFlags |= kFORM;                                                    /* otherwise mark it found */
  82.                     *length = chunkTemplate->container.ckSize;
  83.                     filePosition += sizeof (ContainerChunk);        /* Can't use ckSize because it's the size of the file, not this header */
  84.                     type = chunkTemplate->container.formType;
  85.                     err = noErr;
  86.                 }
  87.                 break;
  88.             case FormatVersionID:                                                            /* Format Version Chunk? */
  89.                 if ((chunkFlags & kFormatVersion) == false) {                                /* see if this chunk already exists */
  90.                     chunkFlags |= kFormatVersion;                                            /* otherwise mark it found */
  91.                     filePosition += chunkTemplate->formatVersion.ckSize + kChunkHeaderSize;    /* calculate next chunk's position */
  92.                     if (chunkTemplate->formatVersion.timestamp != AIFCVersion1) {
  93.                         err = kUnknownFormat;
  94.                     }
  95.                     else {
  96.                         err = noErr;
  97.                     }
  98.                 }
  99.                 break;
  100.             case CommonID:
  101.                 if ((chunkFlags & kCommon) == false) {                                        /* see if this chunk already exists */
  102.                     long double        tempLD    = 0.0;
  103.  
  104.                     chunkFlags |= kCommon;                                                    /* otherwise mark it found */
  105.                     filePosition += chunkTemplate->common.ckSize + kChunkHeaderSize;        /* calculate next chunk's position */
  106.  
  107.                     #ifdef powerc
  108.                         x80told (&(chunkTemplate->common.sampleRate), &tempLD);
  109.                     #else
  110.                         tempLD = chunkTemplate->common.sampleRate;
  111.                     #endif
  112.                     sampleRate = ASoundLongDoubleToFix (tempLD);
  113.  
  114.                     if (type == AIFCID) { 
  115.                         err = SetupDBHeader    (theSoundInfo,
  116.                                             sampleRate,
  117.                                             chunkTemplate->common.sampleSize,
  118.                                             chunkTemplate->common.numChannels,
  119.                                             fixedCompression,
  120.                                             chunkTemplate->extCommon.compressionType);
  121.                         theSoundInfo->needsMasking = false;
  122.                     }
  123.                     else {
  124.                         err = SetupDBHeader    (theSoundInfo,
  125.                                             sampleRate,
  126.                                             chunkTemplate->common.sampleSize,
  127.                                             chunkTemplate->common.numChannels,
  128.                                             notCompressed,
  129.                                             NoneType);
  130.                         if (chunkTemplate->common.sampleSize == kSixteen) {
  131.                             theSoundInfo->needsMasking = false;
  132.                         }
  133.                         else {
  134.                             theSoundInfo->needsMasking = true;
  135.                         }
  136.                     }
  137.                 }
  138.                 break;
  139.             case SoundDataID:
  140.                 if ((chunkFlags & kSoundData) == false) {                                                /* see if this chunk already exists */
  141.  
  142.                     /*    Let's remember where the Sound Data starts, so we can find the position in the file later.
  143.                         The mark will be positioned at the beginning of the chunk, so move 16 bytes past to get past
  144.                         the header information to the data. */
  145.                     *dataStart = filePosition + 16;
  146.                     chunkFlags |= kSoundData;                                                            /* otherwise mark it found */
  147.                     filePosition += chunkTemplate->soundData.ckSize + kChunkHeaderSize;                    /* calculate next chunk's position */
  148.                     err = noErr;
  149.                 }
  150.                 break;
  151.             /*
  152.                 The following list of chunks we don't care about, so we'll just skip over them.
  153.             */
  154.             case MarkerID:
  155.                 if ((chunkFlags & kMarker) == false) {                                                    /* see if this chunk already exists */
  156.                     chunkFlags |= kMarker;                                                                /* otherwise mark it found */
  157.                     filePosition += chunkTemplate->marker.ckSize + kChunkHeaderSize;                    /* calculate next chunk's position */
  158.                     err = noErr;
  159.                 }
  160.                 break;
  161.             case CommentID:
  162.                 if ((chunkFlags & kComment) == false) {                                                    /* see if this chunk already exists */
  163.                     chunkFlags |= kComment;                                                                /* otherwise mark it found */
  164.                     filePosition += chunkTemplate->marker.ckSize + kChunkHeaderSize;                    /* calculate next chunk's position */
  165.                     err = noErr;
  166.                 }
  167.                 break;
  168.             case InstrumentID:
  169.                 if ((chunkFlags & kInstrument) == false) {                                                /* see if this chunk already exists */
  170.                     chunkFlags |= kInstrument;                                                            /* otherwise mark it found */
  171.                     filePosition += chunkTemplate->instrument.ckSize + kChunkHeaderSize;                /* calculate next chunk's position */
  172.                     err = noErr;
  173.                 }
  174.                 break;
  175.             case MIDIDataID:
  176.                 if ((chunkFlags & kMIDIData) == false) {                                                /* see if this chunk already exists */
  177.                     chunkFlags |= kMIDIData;                                                            /* otherwise mark it found */
  178.                     filePosition += chunkTemplate->midiData.ckSize + kChunkHeaderSize;                    /* calculate next chunk's position */
  179.                     err = noErr;
  180.                 }
  181.                 break;
  182.             case AudioRecordingID:
  183.                 if ((chunkFlags & kAudioRecording) == false) {                                            /* see if this chunk already exists */
  184.                     chunkFlags |= kAudioRecording;                                                        /* otherwise mark it found */
  185.                     filePosition += chunkTemplate->audioRecording.ckSize + kChunkHeaderSize;            /* calculate next chunk's position */
  186.                     err = noErr;
  187.                 }
  188.                 break;
  189.             case ApplicationSpecificID:
  190.                 if ((chunkFlags & kApplicationSpecific) == false) {                                        /* see if this chunk already exists */
  191.                     chunkFlags |= kApplicationSpecific;                                                    /* otherwise mark it found */
  192.                     filePosition += chunkTemplate->generic.ckSize + kChunkHeaderSize;                    /* calculate next chunk's position */
  193.                     err = noErr;
  194.                 }
  195.                 break;
  196.             case NameID:
  197.                 if ((chunkFlags & kName) == false) {                                                    /* see if this chunk already exists */
  198.                     chunkFlags |= kName;                                                                /* otherwise mark it found */
  199.                     filePosition += chunkTemplate->generic.ckSize + kChunkHeaderSize;                    /* calculate next chunk's position */
  200.                     err = noErr;
  201.                 }
  202.                 break;
  203.             case AuthorID:
  204.                 if ((chunkFlags & kAuthor) == false) {                                                    /* see if this chunk already exists */
  205.                     chunkFlags |= kAuthor;                                                                /* otherwise mark it found */
  206.                     filePosition += chunkTemplate->generic.ckSize + kChunkHeaderSize;                    /* calculate next chunk's position */
  207.                     err = noErr;
  208.                 }
  209.                 break;
  210.             case CopyrightID:
  211.                 if ((chunkFlags & kCopyright) == false) {                                                /* see if this chunk already exists */
  212.                     chunkFlags |= kCopyright;                                                            /* otherwise mark it found */
  213.                     filePosition += chunkTemplate->generic.ckSize + kChunkHeaderSize;                    /* calculate next chunk's position */
  214.                     err = noErr;
  215.                 }
  216.                 break;
  217.             case AnnotationID:
  218.                 if ((chunkFlags & kAnnotation) == false) {                                                /* see if this chunk already exists */
  219.                     chunkFlags |= kAnnotation;                                                            /* otherwise mark it found */
  220.                     filePosition += chunkTemplate->generic.ckSize + kChunkHeaderSize;                    /* calculate next chunk's position */
  221.                     err = noErr;
  222.                 }
  223.                 break;
  224.             default :                                                                                    /* Unrecognized?? croak. */
  225.                 DebugPrint ("\pran into an undefined chunk!!");
  226.  
  227.                 /*    If we hit an unrecognized chunk, clear chunkFlags to drop out of the loop
  228.                     with the assumed error code. */
  229.                 chunkFlags = kInit;
  230.                 break;
  231.         }
  232.  
  233.     /*    We're only done when the the FORM, FormatVersion, Common and Sound Data chunks.  This is only
  234.         true of this incarnation - your needs may vary, so you'll have to modify the following statement
  235.         accordingly...
  236.         I know, this clause is a pain in the ass:  what it really says is this:
  237.             As long as we have a FORM Chunk and we don't have all of the {Formatversion, Common, SoundData} chunks
  238.             keep going... AND we haven't gotten an error from the file system. */
  239.     } while (stillMoreDataToRead);
  240.  
  241.     if (err != noErr) {
  242.         DebugPrint ("\pError in ASoundGetAIFFHeader");
  243.     }
  244.  
  245.     return err;
  246. }
  247.